/**
 * PEM
 *
 * A class to parse some PEM stuff.
 * Copyright (c) 2007 Henri Torgemane
 *
 * See LICENSE.txt for full license information.
 */
package com.hurlant.util.der
{
	import com.hurlant.crypto.rsa.RSAKey;
	import com.hurlant.math.BigInteger;
	import com.hurlant.util.Base64;

	import flash.utils.ByteArray;
	import com.hurlant.util.Hex;

	public class PEM
	{
		private static const RSA_PRIVATE_KEY_HEADER:String="-----BEGIN RSA PRIVATE KEY-----";
		private static const RSA_PRIVATE_KEY_FOOTER:String="-----END RSA PRIVATE KEY-----";
		private static const RSA_PUBLIC_KEY_HEADER:String="-----BEGIN PUBLIC KEY-----";
		private static const RSA_PUBLIC_KEY_FOOTER:String="-----END PUBLIC KEY-----";
		private static const CERTIFICATE_HEADER:String="-----BEGIN CERTIFICATE-----";
		private static const CERTIFICATE_FOOTER:String="-----END CERTIFICATE-----";



		/**
		 *
		 * Read a structure encoded according to
		 * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
		 * section 11.1.2
		 *
		 * @param str
		 * @return
		 *
		 */
		public static function readRSAPrivateKey(str:String):RSAKey
		{
			var der:ByteArray=extractBinary(RSA_PRIVATE_KEY_HEADER, RSA_PRIVATE_KEY_FOOTER, str);
			if (der == null)
				return null;
			var obj:*=DER.parse(der);
			if (obj is Array)
			{
				var arr:Array=obj as Array;
				// arr[0] is Version. should be 0. should be checked. shoulda woulda coulda.
				return new RSAKey(arr[1], // N
					arr[2].valueOf(), // E
					arr[3], // D
					arr[4], // P
					arr[5], // Q
					arr[6], // DMP1
					arr[7], // DMQ1	
					arr[8]); // IQMP
			}
			else
			{
				// dunno
				return null;
			}
		}


		/**
		 * Read a structure encoded according to some spec somewhere
		 * Also, follows some chunk from
		 * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
		 * section 11.1
		 *
		 * @param str
		 * @return
		 *
		 */
		public static function readRSAPublicKey(str:String):RSAKey
		{
			var der:ByteArray=extractBinary(RSA_PUBLIC_KEY_HEADER, RSA_PUBLIC_KEY_FOOTER, str);
			if (der == null)
				return null;
			var obj:*=DER.parse(der);
			if (obj is Array)
			{
				var arr:Array=obj as Array;
				// arr[0] = [ <some crap that means "rsaEncryption">, null ]; ( apparently, that's an X-509 Algorithm Identifier.
				if (arr[0][0].toString() != OID.RSA_ENCRYPTION)
				{
					return null;
				}
				// arr[1] is a ByteArray begging to be parsed as DER
				arr[1].position=1; // there's a 0x00 byte up front. find out why later. like, read a spec.
				obj=DER.parse(arr[1]);
				if (obj is Array)
				{
					arr=obj as Array;
					// arr[0] = modulus
					// arr[1] = public expt.
					return new RSAKey(arr[0], arr[1]);
				}
				else
				{
					return null;
				}
			}
			else
			{
				// dunno
				return null;
			}
		}

		public static function readCertIntoArray(str:String):ByteArray
		{
			var tmp:ByteArray=extractBinary(CERTIFICATE_HEADER, CERTIFICATE_FOOTER, str);
			return tmp;
		}

		private static function extractBinary(header:String, footer:String, str:String):ByteArray
		{
			var i:int=str.indexOf(header);
			if (i == -1)
				return null;
			i+=header.length;
			var j:int=str.indexOf(footer);
			if (j == -1)
				return null;
			var b64:String=str.substring(i, j);
			// remove whitesapces.
			b64=b64.replace(/\s/mg, '');
			// decode
			return Base64.decodeToByteArray(b64);
		}

	}
}

